﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Newtonsoft.Json;
using JHStock.Update;
using Tools;
using ToolsCXml;
using JHStock.UserForm;
using System.Text.RegularExpressions;
namespace JHStock
{
    public delegate void DelegateFormatData(NetObjectTagstock tagstock, Stock s, string txt);
    public delegate void DelegateOutPutTxt(NetObjectTagstock tagstock, Stock s, string txt);  
    public class FormatDataFunction
    {
        private string _datetype;
        public FormatDataFunction(string datetype)
        {
            if (datetype.EndsWith("ly"))
                datetype = datetype.Replace("ly", "");
            this._datetype = datetype;
        }
        public void FormatKDData(NetObjectTagstock tagstock, Stock s, string txt)
        {
            txt = CutJsonStringHead(txt);
            if (_datetype == "fin")
            {
                tagstock.ObjTag = ConstructFinKdata(s.Code, txt);
            }
            else
            {
                tagstock.ObjTag = ConstructKdata(s.Code, txt);
            }
            tagstock.value = 1;
        }

        private Fhsgs ConstructFinKdata(string stockcode, string txt)
        {
            string filetemplate = "{\"stockcode\":\"[stockcode]\"\r\n,FHSG:[[value]]}";

            try
            {
                QQStocks qs = JsonConvert.DeserializeObject<QQStocks>(txt);
                List<string> kd = qs.data[stockcode.ToLower()].day
                    .Where(r1 => r1.Count == 7)
                   .Select(r2 => r2[6].ToString()).ToList();
                string ss = string.Join(",\r\n", kd);
                filetemplate = filetemplate.Replace("[stockcode]", stockcode)
                            .Replace("[value]", ss);
                Fhsgs fh = JsonConvert.DeserializeObject<Fhsgs>(filetemplate);
                return fh;
            }
            catch
            {
                Fhsgs fh = new Fhsgs();
                fh.stockcode = stockcode;
                fh.FHSG = new List<FHSGStrItem>();
                return fh;
            }
        }
        public static List<KData> ConstructKdata(string stockcode, string txt)
        {
            QQStocks qs = JsonConvert.DeserializeObject<QQStocks>(txt);
            List<KData> kd = qs.data[stockcode.ToLower()].day
               .Select(r =>
               {
                   KData k = new KData();
                   long date =  Convert.ToInt64(r[0].ToString().Replace("-", ""));
                   if (date > Int32.MaxValue)
                   {
                       long year = date / 100000000 - 2017; //小时数据不超过 2017年                      
                       k.date = (int)year * 100000000 + (int)(date % 100000000);
                   }
                   else
                       k.date = (int)date;
                   k.open = (int)(Convert.ToSingle(r[1]) * 100);
                   k.close = (int)(Convert.ToSingle(r[2]) * 100);
                   k.high = (int)(Convert.ToSingle(r[3]) * 100);
                   k.low = (int)(Convert.ToSingle(r[4]) * 100);
                   k.vol = (long)(Convert.ToSingle(r[5]) * 100);
                   k.reservation = 0;
                   if (r.Count == 7)
                   {
                       k.reservation = 1;
                       try
                       {
                           Regex re = new Regex("10(派([0-9.]*)元)?(送([0-9.]*)股)?(转([0-9.]*)股)?");
                           double PX = 0;
                           double SG = 0;
                           double ZZ = 0;
                           Match m = re.Match(r[6].ToString());
                           if (m.Success)
                           {
                               if (m.Groups[2].Success)
                                PX = Convert.ToDouble(m.Groups[2].Value);
                               if (m.Groups[4].Success)
                                   SG = Convert.ToDouble(m.Groups[4].Value);
                               if (m.Groups[6].Success)
                                   ZZ = Convert.ToDouble(m.Groups[6].Value);
                           }
                           k.reservation = (int)((SG + ZZ) * 1000000 + PX * 100);
                           if (k.reservation == 0)
                               k.reservation = 3;
                       }
                       catch//(Exception e) 
                       {
                           k.reservation = 2;
                       }
                       
                   }
                   return k;
               }).ToList();
            return kd;
        } 
        private string CutJsonStringHead(string txt)
        {
            if (txt.IndexOf("=") != -1)
                txt = txt.Substring(txt.IndexOf("=") + 1);
            txt = txt.Replace(_datetype, "day");
            txt = txt.Replace("qfqday", "day");
            return txt;
        }
    }
	public class ThreadUpdateStocksJson{
		public ThreadUpdateStocksJson(Stocks stocks,ThreadUpdateStocksConfig TSC)
	    {
	        bshowtimeout = false;
            _tsc = TSC;
	        _stocks = stocks;
            //_cfg = _stocks.Gcfg;
	        _exceptionfilename = TimeStringTools.NowDateMin() + "_UpdateException.log";         
	        
	        MaxThreadSum = TSC.MaxThreadSum;
	        Tag = new NetObjectTagstock[2000];
            //for (int i = 0; i < 2000; i++)
	            Tag[0] = new NetObjectTagstock();
            foreach (Stock s in _stocks.stocks)
            {
                Tag[s.ID] = new NetObjectTagstock();
                Tag[s.ID].Init(s);
            }
	        showmsg=null;
	    }
        public void SetTagValidValue(List<Stock> Dealstocks)
        {
            foreach (Stock s in Dealstocks)
            {
                if (Tag[s.ID] != null)
                {
                    Tag[s.ID].value = -1;
                }
            }
        }
        public void DownLoadJsonData(Stock s)
        {
            string url = _tsc.UrlTemplate.Replace("[stockcode]", s.Code.ToLower());
            string txt = CWeb.GetWebClient(url,"utf-8");
            try
            {
                if (TSC.FormatData != null) 
                TSC.FormatData(Tag[s.ID], s, txt);               
                Tag[s.ID].value = 1;
                if (TSC.Files.OutPutMode == "singlefile")
                {
                    if (TSC.Files.ThreadOutTxt != null)
                        TSC.Files.ThreadOutTxt(Tag[s.ID],s, txt);
                }
                //List<KData> kd = (List<KData>)Tag[s.ID].ObjTag;
                //foreach(KData k in kd)
                //    if (k.reservation > 0)
                //    {
                //        int date = k.date;
                //        date++;
                //        break;
                //    }
            }
            catch (Exception e)
            {
                Tag[s.ID].txt = txt;
                Tag[s.ID].value = -2;
                MFile.AppendAllText("UpdatePrice.log", s.ID + "  " + Tag[s.ID].txt + "\t" + e.Message + "\r\n\r\n");
            }
        }
		public void UpdateItem(List<Stock> usstocks)
		{
			threadsum = 0;
			threadcompletesum=0;	
			int time = 0;		
			DateTime dt1 = System.DateTime.Now;	
			foreach(Stock s in usstocks){
				while(threadsum==MaxThreadSum){
					time++;
					Thread.Sleep(1);
				}
				Interlocked.Increment(ref threadsum);
				if( time>10){
					TimeSpan ts = System.DateTime.Now.Subtract(dt1);
					if(ts.TotalSeconds>5){
                        if (showmsg != null)
                            showmsg("已完成：" + threadcompletesum + "");
						time=0;
						dt1 = System.DateTime.Now;
					}
				}
				if(threadcompletesum < MaxThreadSum)
					Thread.Sleep(10);
				ThreadUpdateStockJson tus = new ThreadUpdateStockJson(s,this);
				System.Threading.Thread nonParameterThread = new Thread(new ThreadStart(tus.Run));
				nonParameterThread.Start();
			}
			while(threadsum > 0 )
				Thread.Sleep(10);
            if(showmsg!=null)
            showmsg("已完成：" + threadcompletesum + "");
		}
        private Stocks _stocks;
        //private GlobalConfig _cfg;   
	    public int MaxThreadSum;
	    public int threadsum;
	    public int threadcompletesum;
	    public ShowDeleGate showmsg;
	    public bool bshowtimeout;
	    private string _exceptionfilename;
	    public NetObjectTagstock[] Tag;
        public ThreadUpdateStocksConfig _tsc;
        public ThreadUpdateStocksConfig TSC{get {return _tsc;}}
        public List<Stock> Stocks { get { return _stocks.stocks; } }

    }
	public class ThreadUpdateStockJson{
    	private Stock s;
    	private ThreadUpdateStocksJson _parent;
    	public ThreadUpdateStockJson(Stock s,ThreadUpdateStocksJson parent){
    		this.s = s;
    		this._parent = parent;
    	}
    	public void Run(){
    		try{
    			_parent.DownLoadJsonData(s);
    		}catch(Exception e){
    			MFile.AppendAllText(_parent.TSC.Files.ChildErrorlog,s.ID+"\t"+e.Message+"\r\n");
    		}
    		Interlocked.Decrement(ref _parent.threadsum);
			Interlocked.Increment(ref _parent.threadcompletesum);
    	}
    }
    public class ThreadUpdateStocksConfig
    {
        public ThreadUpdateStocksConfig(string datetype, int daylength)
        {
            UrlT  = new ThreadUpdateUrlTemplate(datetype);
            _daylength = daylength.ToString();
            MaxThreadSum = 1;
            FormatData = null;
            Debug = false;
        }
        public string UrlTemplate{get {return UrlT.UrlTemplate.Replace("[dayscount]",_daylength);}}
        public ThreadUpdateUrlTemplate UrlT;
        public ThreadUpdateJsonFiles Files;
        private string _daylength;
        public int MaxThreadSum { get; set; }
        public DelegateFormatData FormatData { get; set; }
        public bool Debug { get; set; }
    }
    public class ThreadUpdateUrlTemplate
    {        
        private string _datetype;
        private string urlt;
        public ThreadUpdateUrlTemplate(string datetype, bool UnQfq = false)
        {
            this._datetype = datetype;
            if (!"|m1ly|m5ly|m15ly|m30ly|m60ly|dayly|monthly|weekly|maincwfx".Contains("|" + datetype + "|"))
                datetype = "dayly";
            if ("|m1ly|m5ly|m15ly|m30ly|m60ly|".Contains(datetype))
            {
                urlt = @"http://ifzq.gtimg.cn/appstock/app/kline/mkline?param=[stockcode],[datetype],,[dayscount]&_var=m1_today";
                //tolower
                urlt = urlt.Replace("[datetype]", _datetype.Substring(0,_datetype.Length-2));
            }

            if (_datetype == "weekly")
                urlt = @"http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_weekqfq&param=[stockcode],week,,,[dayscount],qfq";
            if (_datetype == "monthly")
                urlt = @"http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_monthqfq&param=[stockcode],month,,,[dayscount],qfq";
            if(_datetype == "dayly")
                 urlt =  @"http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?_var=kline_day&param=[stockcode],day,,,[dayscount],qfq";
            if (_datetype == "maincwfx")
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/MainTargetAjax?type=[type]&code=[stockcode]";
            if (_datetype == "DubangAnalysis")
            {
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/DubangAnalysisAjax?code=[stockcode]";
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/zcfzbAjax?companyType=4&reportDateType=0&reportType=1&endDate=&code=SH600856";
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/lrbAjax?companyType=4&reportDateType=0&reportType=1&endDate=&code=SH600856";
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/xjllbAjax?companyType=4&reportDateType=0&reportType=1&endDate=&code=SH600856";
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/PercentAjax_Index?companyType=4&reportDateType=0&reportType=1&endDate=&code=SH600856";
                urlt = @"http://f10.eastmoney.com/NewFinanceAnalysis/PercentAjax?companyType=4&reportDateType=0&reportType=1&endDate=&code=SH600856";
            }
            if (UnQfq)
                urlt = urlt.Replace(",qfq", ",bfq");
        }
        public  void SetParam(string src, string dst)
        {
            urlt = urlt.Replace(src, dst);
        }
        public string UrlTemplate {get {return urlt;}}

    }
    public class ThreadUpdateJsonFiles
    {
        public ThreadUpdateJsonFiles()
        {
            ChildErrorlog = "QQDaylyError.log";
            OutPutMode = "unifile";
        }
        private ToolsCXml.BETag btyear = new ToolsCXml.BETag("[nflb\":#@#@-@#@#]");
        private ToolsCXml.BETag btcheck = new ToolsCXml.BETag("[:#@#@{-}@#@#}]");

        public string ChildErrorlog { get; set; }
        public string OutPutMode { get; set; }
        public DelegateOutPutTxt ThreadOutTxt;       
    }
    
    public class NetObjectTagstock
    {
        public NetObjectTagstock()  // New -100  Init 0   fordeal -1  dealed = 1  except -2
        {
            index = 0;
            value = -100;
            s = null;
            txt = "";
            TagClass = "";
        }
        public NetObjectTagstock(Stock s)
        {
            Init(s);
        }
        public void Init(Stock s)
        {
            this.s = s;
            index = s.ID;
            value = 0;
        }
        public void SetLatestKData(KData kData)
        {
            _latestkd = kData;
        }
        public void SetOldestKData(KData kData)
        {
            OldestKDate = kData;
        }

        public Object ObjTag { get; set; }
        public int index;
        public int value;
        public string TagClass;
        public bool Valid { get; set; }
        [JsonProperty]
        private KData _latestkd;

        [JsonIgnore]
        public KData OldestKDate { get; set;}
        [JsonIgnore]
        public KData LatestKData { get { return _latestkd; } }
        [JsonIgnore]
        public Stock s;    // for initlize
        [JsonIgnore]
        public string txt;	// for out debug infor
    }
    public class NetObjectTagstocks
    {
        public NetObjectTagstocks(DateTime StoreDate, NetObjectTagstock[] netTag)
        {
            this.StoreDate = StoreDate;
            this.Tag = netTag;
        }
        public DateTime StoreDate { get; set; }
        public NetObjectTagstock[] Tag { get; set; }
        public void Save(string path)
        {
            MFile.WriteAllText(path, JsonConvert.SerializeObject(this));
        }
    }
    public class LocalKdTagstocks
    {
        public LocalKdTagstocks(DateTime StoreDate, int length)
        {
            this.StoreDate = StoreDate;
            this.Tag = new LocalKdTagstock[length];
        }
        public void Save(string path)
        {
            MFile.WriteAllText(path, JsonConvert.SerializeObject(this));
        }
        public void Init(NetObjectTagstocks netTags)
        {
            foreach (NetObjectTagstock nt in netTags.Tag)
            {
                if (nt!=null && nt.s != null && nt.index >= 0 )
                {
                    if(Tag[nt.index] == null)
                        Tag[nt.index] = new LocalKdTagstock();
                   
                    Tag[nt.index].Init(nt.s);
                    if (nt.ObjTag != null)
                    {
                        Tag[nt.index].kd = (List<KData>)nt.ObjTag;
                        Tag[nt.index].Latestkd = nt.LatestKData ;
                        Tag[nt.index].Valid = true;
                    }

                }
            }
        }
        public int StoreIntDate()
        {
            return this.StoreDate.Year * 10000 + this.StoreDate.Month * 100 + this.StoreDate.Day;
        }

        public int StoreFinDate{ get; set; }
        public DateTime StoreDate { get; set; }
        public LocalKdTagstock[] Tag { get; set; }
    }
    public class LocalKdTagstock
    {
        public LocalKdTagstock()
        {
            index = 0;
            value = -100;
            s = null;
            txt = "";
        }
        public LocalKdTagstock(Stock s)
        {
            Init(s);
        }
        public void Init(Stock s)
        {
            this.s = s;
            index = s.ID;
            value = 0;
        }
       
        [JsonIgnore]
        public List<KData> Akd
        {
            get
            {
                if (Latestkd.date == 0)
                    return kd;
                List<KData> akd = new List<KData>(kd);
                akd.Add(Latestkd);
                return akd;
            }
        }
        [JsonIgnore]
        public bool HasFin
        {
            get
            {
                if(kd==null)
                    return false;
                return Latestkd.reservation > 0 || kd.Exists(r => r.reservation > 0);
            }
        }

        public int index;
        public int value;
        public bool Valid { get; set; }       
        public KData Latestkd;
        public List<KData> kd { get; set; }
        [JsonIgnore]
        public Stock s;    // for initlize
        [JsonIgnore]
        public string txt;	 // for out debug infor
    }
}
